Header menu logo FSharp.Analyzers.SDK

Unit testing an analyzer

To help analyzer authors testing their analyzers, there's a dedicated testing package. It contains easy to use utility functions to create a context for the analyzer and assertion helpers.

FSharp.Analyzers.SDK.Testing.mkOptionsFromProject creates the FSharpProjectOptions for the given framework (e.g. net7.0) and the given list of packages to reference. FSharp.Analyzers.SDK.Testing.getContext then takes the FSharpProjectOptions and the source code to test and creates a CliContext you can pass along to your analyzer function. The module FSharp.Analyzers.SDK.Testing.Assert offers various functions to help with assertion statements from your favorite unit testing framework. For a complete example of an unit testing project, take a look at OptionAnalyzer.Test in the samples folder of the SDK repository.

open FSharp.Compiler.CodeAnalysis
open FSharp.Analyzers.SDK.Testing
open OptionAnalyzer
open NUnit.Framework

let mutable projectOptions: FSharpProjectOptions = FSharpProjectOptions.zero

[<SetUp>]
let Setup () =
    task {
        let! opts =
            mkOptionsFromProject
                "net7.0"
                [
                  // The SDK uses this in a "dotnet add package x --version y" command
                  // to generate the needed FSharpProjectOptions
                  { Name = "Newtonsoft.Json"
                    Version = "13.0.3" } ]

        projectOptions <- opts
    }

[<Test>]
let ``warnings are emitted`` () =
    async {
        let source =
            """
module M

let notUsed() =
    let option : Option<int> = None
    option.Value
    """

        let ctx = getContext projectOptions source
        let! msgs = optionValueAnalyzer ctx
        Assert.IsNotEmpty msgs
        Assert.IsTrue(Assert.messageContains "Option.Value" msgs[0])
    }

Previous Next

Multiple items
namespace FSharp

--------------------
namespace Microsoft.FSharp
namespace FSharp.Compiler
namespace FSharp.Compiler.CodeAnalysis
namespace FSharp.Analyzers
namespace FSharp.Analyzers.SDK
module Testing from FSharp.Analyzers.SDK
module OptionAnalyzer
namespace NUnit
namespace NUnit.Framework
val mutable projectOptions: FSharpProjectOptions
type FSharpProjectOptions = { ProjectFileName: string ProjectId: string option SourceFiles: string array OtherOptions: string array ReferencedProjects: FSharpReferencedProject array IsIncompleteTypeCheckEnvironment: bool UseScriptResolutionRules: bool LoadTime: DateTime UnresolvedReferences: FSharpUnresolvedReferencesSet option OriginalLoadReferences: (range * string * string) list ... } member Equals: FSharpProjectOptions * IEqualityComparer -> bool
property FSharpProjectOptions.zero: FSharpProjectOptions with get
Multiple items
type SetUpAttribute = inherit NUnitAttribute new: unit -> unit

--------------------
SetUpAttribute() : SetUpAttribute
val Setup: unit -> System.Threading.Tasks.Task<unit>
val task: TaskBuilder
val opts: FSharpProjectOptions
val mkOptionsFromProject: framework: string -> additionalPkgs: Package list -> System.Threading.Tasks.Task<FSharpProjectOptions>
<summary>Creates a classlib project in a temporary folder to gather the needed FSharpProjectOptions.</summary>
<param name="framework">The target framework for the tested code to use. E.g. net6.0, net7.0</param>
<param name="additionalPkgs">A list of additional packages that should be referenced. The tested code can use these.</param>
<returns>FSharpProjectOptions</returns>
Multiple items
type TestAttribute = inherit NUnitAttribute interface ISimpleTestBuilder interface IApplyToTest interface IImplyFixture new: unit -> unit member ApplyToTest: test: Test -> unit member BuildFrom: method: IMethodInfo * suite: Test -> TestMethod member Author: string member Description: string member ExpectedResult: obj ...

--------------------
TestAttribute() : TestAttribute
val async: AsyncBuilder
val source: string
val ctx: FSharp.Analyzers.SDK.CliContext
val getContext: opts: FSharpProjectOptions -> source: string -> FSharp.Analyzers.SDK.CliContext
val msgs: FSharp.Analyzers.SDK.Message list
val optionValueAnalyzer: ctx: FSharp.Analyzers.SDK.CliContext -> Async<FSharp.Analyzers.SDK.Message list>
type Assert = static member AreEqual: expected: float * actual: float * delta: float * message: string * [<ParamArray>] args: obj array -> unit + 5 overloads static member AreNotEqual: expected: obj * actual: obj * message: string * [<ParamArray>] args: obj array -> unit + 1 overload static member AreNotSame: expected: obj * actual: obj * message: string * [<ParamArray>] args: obj array -> unit + 1 overload static member AreSame: expected: obj * actual: obj * message: string * [<ParamArray>] args: obj array -> unit + 1 overload static member ByVal: actual: obj * expression: IResolveConstraint -> unit + 1 overload static member Catch: code: TestDelegate * message: string * [<ParamArray>] args: obj array -> exn + 5 overloads static member CatchAsync: code: AsyncTestDelegate * message: string * [<ParamArray>] args: obj array -> exn + 5 overloads static member Contains: expected: obj * actual: ICollection * message: string * [<ParamArray>] args: obj array -> unit + 1 overload static member DoesNotThrow: code: TestDelegate * message: string * [<ParamArray>] args: obj array -> unit + 1 overload static member DoesNotThrowAsync: code: AsyncTestDelegate * message: string * [<ParamArray>] args: obj array -> unit + 1 overload ...
Assert.IsNotEmpty(collection: System.Collections.IEnumerable) : unit
Assert.IsNotEmpty(aString: string) : unit
Assert.IsNotEmpty(collection: System.Collections.IEnumerable, message: string, [<System.ParamArray>] args: obj array) : unit
Assert.IsNotEmpty(aString: string, message: string, [<System.ParamArray>] args: obj array) : unit
Assert.IsTrue(condition: bool) : unit
Assert.IsTrue(condition: System.Nullable<bool>) : unit
Assert.IsTrue(condition: bool, message: string, [<System.ParamArray>] args: obj array) : unit
Assert.IsTrue(condition: System.Nullable<bool>, message: string, [<System.ParamArray>] args: obj array) : unit
val messageContains: expectedContent: string -> msg: FSharp.Analyzers.SDK.Message -> bool

Type something to start searching.